#include <stdio.h>
#include <string.h>
#include <err.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include "bspatch.h"

#include "ghttp/ghttp.h"

#include "bzip2/bzlib.h"

#define PATH "/Users/wdj/AndroidStudioProjects/android_app/app/build/outputs/apk/version"

typedef struct {
    char scheme[10];
    char host[128];
    unsigned int port;
    char path[512];
    char query[1024];
} URL;

URL parseURL(const char *urlStr){
    URL url = {
            .scheme = "http",
            .port = 80,
    };
    int sts = 0;
    char scheme[10] = "";
    char host[128] = "";
    char port[5] = "";
    char path[512] = "";
    char query[1024] = "";

    for(int i=0; i < strlen(urlStr);i++){
        switch (urlStr[i]){
            case ':':;
                if(strlen(scheme) == 0){
                    for(int z=0;z<i;z++){
                        scheme[strlen(scheme)] = urlStr[z];
                    }
                }else if(url.port == 0){
                    sts = 2;
                }
                break;

            case '/':
                if(urlStr[i + 1] == '/')continue;

                if (strlen(host) == 0){
                    sts = 1;
                }else if(strlen(path) <= 1){
                    path[0] = '/';
                    sts = 3;
                }else if(strlen(host) > 0 || strlen(port) > 0){
                    sts = 0;
                }
                break;

            case '?':
                sts = 4;
                break;

            default:

                switch (sts){
                    case 1:
                        host[strlen(host)] = urlStr[i];
                        break;
                    case 2:
                        port[strlen(port)] = urlStr[i];
                        break;
                    case 3:
                        path[strlen(path)] = urlStr[i];
                        break;
                    case 4:
                        query[strlen(query)] = urlStr[i];
                        break;
                    default:break;
                }

                break;

        }
    }

    strcpy(url.scheme, scheme);
    strcpy(url.host, host);
    strcpy(url.path, path);
    strcpy(url.query, query);
    url.port = (unsigned int) atoi(port);

    return url;
}

const char *get_ip_by_host(const char *hostname){
    struct hostent *host = gethostbyname(hostname);
    struct in_addr baidu_addr;
    baidu_addr.s_addr = (in_addr_t) *(unsigned long * ) host->h_addr_list[0];
    const char *ip = inet_ntoa(baidu_addr);
    return ip;
}

void http_get(char *url){

    int fd;
    int len;
    struct sockaddr_in remote_addr;
    char buf[BUFSIZ];
    URL uri = parseURL(url);

    memset(&remote_addr, 0, sizeof(remote_addr));
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_addr.s_addr = inet_addr(get_ip_by_host(uri.host));
    remote_addr.sin_port = htons(uri.port == 0 ? 80 : uri.port);

    if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0){
        err(1, "socket error.");
    }

    if(connect(fd, (struct sockaddr*)&remote_addr, sizeof(struct sockaddr)) < 0){
        err(1, "connect error.");
    }

    char body[BUFSIZ];
    sprintf(body, "GET %s HTTP/1.0\r\n"
            "Connection: close\r\n"
            "Host: %s\r\n"
            "User-Agent: MSClient 1.0\r\n"
            "\r\n",
            url,
            uri.host
    );

    printf("send body: %s", body);
    ssize_t sLen = send(fd, body, strlen(body), 0);
    printf("send len: %ld\n", sLen);

    ssize_t recvLen;

    do{
        recvLen = recv(fd, buf, BUFSIZ, 0);
        char a[recvLen];
        strncpy(a, buf, (size_t) recvLen);
        printf("%s", a);
    }while (recvLen > 0);

    close(fd);
}

int main(int argc, char *argv[]) {

    const char oldPath[128] = PATH "/v2.1.0-3233.zip";
    const char newPath[128] = PATH "/v2.1.0-3234.zip";
    const char patchPath[128] = PATH "/v2.1.0-3233_v2.1.0-3234.patch";

    //sprintf(oldPath, "%s/v2.1.0-3233.zip", PATH);
    //sprintf(newPath, "%s/v2.1.0-3234.zip", PATH);
    //sprintf(patchPath, "%s/v2.1.0-3233_v2.1.0-3234.patch", PATH);
//    if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);

    //int sts = applyPatch(oldPath, newPath, patchPath);
//    int sts = applyPatch(argv[1], argv[2], argv[3]);

    //printf("status: %d", sts);

    /*URL url = parseURL("https://www.baidu.com:1212/index.php?query=123&abc=123123");
    printf("schmea: %s\n"
                   "host: %s\n"
                   "port: %d\n"
                   "path: %s\n"
                   "query: %s\n",
           url.scheme,
           url.host,
           url.port,
           url.path,
           url.query
    );

    for (int i = 0; i < 1; ++i) {
        http_get("https://www.baidu.com/");
    }
    printf("success.\n");*/


    char *uri = "http://121.40.166.132/AdPagePosition/Details/Query.json";
    ghttp_request *request = NULL;
    ghttp_status status;
    char *buf;
    int bytes_read;

    request = ghttp_request_new();
    if(ghttp_set_uri(request, uri) == -1)
        exit(-1);
    if(ghttp_set_type(request, ghttp_type_post) == -1)
        exit(-1);

    char *body = "{\"header\":{\"auth\":\"\",\"method\":\"POST\",\"ver\":\"1.0\",\"source\":\"MS\",\"act\":\"\"},\"body\":{\"adPagePositionCode\":\"job_fair_left_banner\"}}";
    ghttp_set_header(request, "Content-Type", "application/json");
    ghttp_set_body(request, body, (int) strlen(body));
    ghttp_prepare(request);
    status = ghttp_process(request);
    if(status == ghttp_error)
        exit(-1);
    /* OK, done */
    printf("Status code -> %d\n", ghttp_status_code(request));
    buf = ghttp_get_body(request);
    bytes_read = ghttp_get_body_len(request);

    printf("%s", buf);
    printf("\n%d\n", bytes_read );

    ghttp_close(request);
    free(buf);

    return 0;
}